! dist_recon module
!
! Purpose:
!   (1) Reconstruct the continuous distribution of unknown variable from
!   data in discrete and irregular form. Adopting methods include:
!     a. Partition of Unity.
!   (2) Calculate the derivative of unknown variable in any order.
!
! Author:
!   Name: DONG Li
!   Email: dongli@lasg.iap.ac.cn

module dist_recon

    use common_info
    use space_manager
    use dynamic_quantities, only: &
        np => num_parcel,         &
        nq => num_quantity,       &
        x => location,            &
        f => quantities,          &
        dynamic_quantities_init,  &
        dynamic_quantities_is_initialized
    use partition_of_unity
    use sample_data
    use message
    use run_manager

    implicit none

    private

    public dist_recon_init
    public dist_recon_finalize
    public dist_recon_approximate
    public dist_recon_evaluate
    public dist_recon_derivative
    public dist_recon_integrate

    integer, parameter, public :: op_s = 1
    integer, parameter, public :: op_m = 2

contains

    subroutine dist_recon_init(namelist_file)
        character(*), intent(in) :: namelist_file

        integer, allocatable :: sample_nx(:)
        integer :: i, j, k
        integer :: temp1, temp2
        integer, allocatable :: o(:)

        ! module dependencies
        if(.not. dynamic_quantities_is_initialized()) then
            call message_show(ERROR_MSG,         &
                "dist_recon", "dist_recon_init", &
                """dist_recon"" needs "          &
                // """dynamic_quantities"" "     &
                // "to be initialized first")
            call run_manager_end_run
        end if
 
        call partition_of_unity_init(namelist_file) ! maybe other file

        call run_manager_register_end( &
            "dist_recon",              &
            "dist_recon_finalize",     &
            dist_recon_finalize)

        return
    end subroutine dist_recon_init

    subroutine dist_recon_finalize

        call partition_of_unity_finalize

        return
    end subroutine dist_recon_finalize

    subroutine dist_recon_approximate(qi)
        integer, intent(in) :: qi

        call partition_of_unity_approximate(qi)

        return
    end subroutine dist_recon_approximate

    subroutine dist_recon_derivative(qi, l, o, d)
        integer, intent(in) :: qi
        integer, intent(in) :: l   ! dimension of derivative
        integer, intent(in) :: o   ! order of derivative
        real, intent(out) :: d(np) ! derivative

        call partition_of_unity_derivative(qi, np, x, l, o, d)

        return
    end subroutine dist_recon_derivative

    ! integrate quantity distribution (numerical integration)

    subroutine dist_recon_integrate(op_type, v, qi1, qi2)
        integer, intent(in) :: op_type
        real, intent(out) :: v
        integer, intent(in) :: qi1
        integer, intent(in), optional :: qi2

        real :: f1(num_sample), f2(num_sample)
        integer :: i

        select case(op_type)
        case(op_s)
            call partition_of_unity_evaluate(qi1, num_sample, sample_x, f1)
            v = sum(f1)*volume
        case(op_m)
            call partition_of_unity_evaluate(qi1, num_sample, sample_x, f1)
            call partition_of_unity_evaluate(qi2, num_sample, sample_x, f2)
            v = sum(f1*f2)*volume
        end select

        return
    end subroutine dist_recon_integrate

    subroutine dist_recon_evaluate(qi, x1, f1)
        integer, intent(in) :: qi
        real, intent(in) :: x1(num_dim)
        real, intent(out) :: f1

        call partition_of_unity_evaluate(qi, x1, f1)

        return 
    end subroutine dist_recon_evaluate

end module dist_recon
